//
//	(c) 2009 Andrew Kalmacky
//

#ifndef _K_ATOMIC_TEST_H_
#define _K_ATOMIC_TEST_H_

#ifdef AK_MT
#include "atomic.h"
#else
#include "non_atomic.h"
#endif

#define CHECK(COND) log::info::assert((COND), STR(COND) T_(" ") STR(__FILE__) T_(":") STR(__LINE__))

namespace ak
{
#ifdef AK_MT
	namespace tm=::std;
#else
	namespace tm=non_atomic;
#endif

	using tm::atomic;
	using tm::memory_order;
	using tm::memory_order_relaxed;
	using tm::memory_order_acquire;
	using tm::memory_order_release; 
	using tm::memory_order_acq_rel;

	class AtomicTest
	{
		typedef Log::Logger<AtomicTest, Log::lv_Verbose> log;
	public:
		AtomicTest()
		{
			buildability_test();
			basic_operations();
			log::info("ok");
		}

		void buildability_test()
		{
			atomic<int> ai;
			int i;
			buildability_test_step<int>(ai, i);

			atomic<int*> ap;
			int* p = &i;
			buildability_test_step<int*>(ap, p);

			i = *ap;
		}

		template<typename T> void buildability_test_step(atomic<T>& v, T& t)
		{
			v.store(t);
			v.store(t, memory_order_relaxed);
			v.store(t, memory_order_release);

			v.load(memory_order_relaxed);
			v.load();

			v.exchange(t, memory_order_relaxed);
			v.exchange(t);

			v.compare_exchange_strong(t, t);
			v.compare_exchange_strong(t, t, memory_order_relaxed);
			v.compare_exchange_strong(t, t, memory_order_relaxed, memory_order_relaxed);

			atomic<T> temp = v;
			v = temp;
			v += 12;
			v -= 12;
			v++;
			++v;
			v--;
			--v;
		}

		void basic_operations()
		{
			atomic<int> i = 1;
			CHECK(i == 1);

			CHECK(++i == 2);
			CHECK(i == 2);
			CHECK(i++ == 2);
			CHECK(i == 3);

			CHECK(--i == 2);
			CHECK(i == 2);
			CHECK(i-- == 2);
			CHECK(i == 1);

			atomic<int> j;
			CHECK(j == 0);
			CHECK(i + j == 1);
		}

	} atomic_test;

}

#undef CHECK
const char_t* const ak::AtomicTest::log::prefix = T_("[atomic_test]");

#endif // _K_ATOMIC_TEST_H_
